//------------------------------------------------------------------------------
// <copyright company="Telligent Systems">
//     Copyright (c) Telligent Systems Corporation.  All rights reserved.
// </copyright> 
//------------------------------------------------------------------------------

using System;
using System.ComponentModel;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace CommunityServer.Controls {

	/// <summary>
	/// An outlook-style panel bar for showing multiple content panels with associated buttons for showing them.
	/// </summary>
	public class CollapseBar : WebControl, IPostBackEventHandler, IPostBackDataHandler {

		#region Properties

		/// <exclude/>
		protected override HtmlTextWriterTag TagKey {
			get {
				return HtmlTextWriterTag.Div;
			}
		}

		/// <summary>
		/// Gets or sets the name of the current item.
		/// </summary>
		[
		Category( "Appearance" ),
		DefaultValue( "" ),
		MergableProperty( false ),
		]
		public virtual String CurrentItem {
			get {
				Object savedState = this.ViewState["CurrentItem"];
				if ( savedState != null  ) {
					return (String)savedState;
				}
				return String.Empty;
			}
			set {
				this.ViewState["CurrentItem"] = value;
			}
		}

		/// <summary>
		/// Gets the collection of items contained by the CollapseBar.
		/// </summary>
		[
		NotifyParentProperty( true ),
		DesignerSerializationVisibility( DesignerSerializationVisibility.Content ),
		PersistenceMode( PersistenceMode.InnerProperty ),
		MergableProperty( false ),
		]
		public virtual CollapseBarItemCollection Items {
			get {
				if ( _items == null ) {
					_items = new CollapseBarItemCollection( this );
				}
				return _items;
			}
		}
		private CollapseBarItemCollection _items;

		/// <summary>
		/// Gets the style applied to the current item's selection button.
		/// </summary>
		[
		Category( "Style" ),
		NotifyParentProperty( true ),
		DesignerSerializationVisibility( DesignerSerializationVisibility.Content ),
		PersistenceMode( PersistenceMode.InnerProperty ),
		]
		public virtual System.Web.UI.WebControls.Style CurrentButtonStyle {
			get {
				if ( _currentButtonStyle == null ) {
					_currentButtonStyle = new System.Web.UI.WebControls.Style();
					if ( this.IsTrackingViewState ) {
						((IStateManager)_currentButtonStyle).TrackViewState();
					}
				}
				return _currentButtonStyle;
			}
		}
		private System.Web.UI.WebControls.Style _currentButtonStyle;

		/// <summary>
		/// Gets the style applied to each item's selection button.
		/// </summary>
		[
		Category( "Style" ),
		NotifyParentProperty( true ),
		DesignerSerializationVisibility( DesignerSerializationVisibility.Content ),
		PersistenceMode( PersistenceMode.InnerProperty ),
		]
		public virtual System.Web.UI.WebControls.Style ButtonStyle {
			get {
				if ( _buttonStyle == null ) {
					_buttonStyle = new System.Web.UI.WebControls.Style();
					if ( this.IsTrackingViewState ) {
						((IStateManager)_buttonStyle).TrackViewState();
					}
				}
				return _buttonStyle;
			}
		}
		private System.Web.UI.WebControls.Style _buttonStyle;

		/// <summary>
		/// Gets the style applied to the content area.
		/// </summary>
		[
		Category( "Style" ),
		NotifyParentProperty( true ),
		DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
		PersistenceMode(PersistenceMode.InnerProperty),
		]
		public System.Web.UI.WebControls.Style ContentStyle {
			get {
				if ( _contentStyle == null ) {
					_contentStyle = new System.Web.UI.WebControls.Style();
					if ( IsTrackingViewState ) {
						((IStateManager)_contentStyle).TrackViewState();
					}
				}
				return _contentStyle;
			}
		}
		private System.Web.UI.WebControls.Style _contentStyle;

		
		private String ClientSideCurrentItemTrackerID {
			get {
				return this.UniqueID + ":CurrentItemTracker";
			}
		}

		
		private String ActiveItem {
			get {
				if ( _activeItem == null ) {
					_activeItem = this.DetermineActiveItem();
				}
				return _activeItem;
			}
		}
		private String _activeItem;

		private String DetermineActiveItem() {
			if ( this.Items.Count == 0 ) {
				return "";
			}

			String currentItem = this.CurrentItem;

			Boolean currentItemFound = false;
			foreach( CollapseBarItem item in this.Items ) {
				if ( item.Title == currentItem ) {
					currentItemFound = true;
					break;
				}
			}
			if ( !currentItemFound ) {
				currentItem = this.Items[ 0 ].Title;
			}

			return currentItem;
		}


		
		#endregion

		#region ViewState

		/// <exclude/>
		protected override void LoadViewState( object savedState ) {
			if ( savedState == null ) {
				base.LoadViewState( null );
				return;
			}

			Object[] state = savedState as Object[];
			if ( state == null || state.Length != 4 ) {
				throw new ArgumentException( "Invalid ViewState" );
			} else {
				base.LoadViewState( state[0] );
				if ( state[1] != null ) {
					((IStateManager)ButtonStyle).LoadViewState( state[1] );
				}
				if ( state[2] != null ) {
					((IStateManager)CurrentButtonStyle).LoadViewState( state[2] );
				}
				if ( state[3] != null ) {
					((IStateManager)ContentStyle).LoadViewState( state[3] );
				}
			}
		}

		/// <exclude/>
		protected override object SaveViewState() {
			Object[] state = new Object[4];
			state[0] = base.SaveViewState();
			state[1] = _buttonStyle == null ? null : ((IStateManager)_buttonStyle).SaveViewState();
			state[2] = _currentButtonStyle == null ? null : ((IStateManager)_currentButtonStyle).SaveViewState();
			state[3] = _contentStyle == null ? null : ((IStateManager)_contentStyle).SaveViewState();
			for( Int32 i = 0; i < state.Length; i++ ) {
				if ( state[i] != null ) {
					return state;
				}
			}
			return null;
		}

		/// <exclude/>
		protected override void TrackViewState() {
			base.TrackViewState();
			if ( _buttonStyle != null ) {
				((IStateManager)_buttonStyle).TrackViewState();
			}
			if ( _currentButtonStyle != null ) {
				((IStateManager)_currentButtonStyle).TrackViewState();
			}
			if ( _contentStyle != null ) {
				((IStateManager)_contentStyle).TrackViewState();
			}
		}

		#endregion

		#region Lifecycle

		/// <exclude/>
		protected override ControlCollection CreateControlCollection() {
			return new CollapseBarControlCollection( this );
		}
		/// <exclude/>
		protected override void OnLoad(EventArgs e) {
			this.LoadStateCookie();
			base.OnLoad( e );
		}

		/// <exclude/>
		protected override void OnPreRender( EventArgs e ) {
			base.OnPreRender( e );
			if ( this.Page != null ) {
				this.Page.RegisterRequiresPostBack( this );
				if ( this.RenderUpLevel ) {
					this.RegisterClientScript();
				}
			}
			this.SaveStateCookie();
		}

		/// <exclude/>
		protected override void Render( HtmlTextWriter writer ) {
			if ( this.Page != null ) {
				this.Page.VerifyRenderingInServerForm( this );
			}
			base.Render( writer );
		}

		/// <exclude/>
		protected override void RenderContents(HtmlTextWriter writer) {
			if ( this.Items.Count > 0 ) {
				if ( RenderUpLevel ) {
					RenderContentsUpLevel( writer );
				} else {
					RenderContentsDownLevel( writer );
				}
			}
		}

		
		#region Render UpLevel

		private void RenderContentsUpLevel( HtmlTextWriter writer ) {
			RenderUpLevelButtons( writer );
			RenderUpLevelItems( writer );
		}

		private void RenderUpLevelItems( HtmlTextWriter writer ) {
			foreach( CollapseBarItem item in this.Items ) {
				if ( item.Visible ) {

					if ( item.Title != this.ActiveItem ) {
						writer.AddStyleAttribute( "display", "none" );
					}

					if ( !this.Height.IsEmpty ) {
						writer.AddStyleAttribute( "height", "100%" );
					}

					this.ContentStyle.AddAttributesToRender( writer );
					writer.RenderBeginTag( "div" );
			
					item.RenderControl( writer );
			
					writer.RenderEndTag();

				}
			}
		}

		private void RenderUpLevelButtons( HtmlTextWriter writer ) {
			foreach ( CollapseBarItem item in this.Items ) {
				if ( item.Visible ) {
				
					Boolean itemIsCurrent = ( item.Title == this.ActiveItem );

					if ( !itemIsCurrent ) {
						writer.AddAttribute( HtmlTextWriterAttribute.Onclick, this.Page.GetPostBackEventReference( this, item.Title ) );
						writer.AddStyleAttribute( "cursor", "pointer" );
					}

					System.Web.UI.WebControls.Style itemStyle = new System.Web.UI.WebControls.Style();
					if ( itemIsCurrent ) {
						itemStyle.CopyFrom( this.CurrentButtonStyle );
					}
					itemStyle.MergeWith( this.ButtonStyle );
					itemStyle.AddAttributesToRender( writer );
					writer.AddStyleAttribute( "padding", "5px" );
					writer.AddStyleAttribute( "white-space", "nowrap" );
					writer.RenderBeginTag( "div" );


					HyperLink buttonControl = new HyperLink();
					if ( !itemIsCurrent && this.Page != null ) {
						buttonControl.NavigateUrl = this.Page.GetPostBackClientHyperlink( this, item.Title );
					} else {
						buttonControl.NavigateUrl = "";
					}
					buttonControl.BorderWidth = Unit.Pixel( 0 );
					buttonControl.ForeColor = itemStyle.ForeColor;
					buttonControl.Text = item.Title;
					buttonControl.RenderControl( writer );


					writer.RenderEndTag();

				}
			}
		}

		
		#endregion

		#region Render DownLevel

		private void RenderContentsDownLevel( HtmlTextWriter writer ) {
			RenderDownLevelButtons( writer );
			RenderDownLevelCurrentItem( writer );
		}

		private void RenderDownLevelButtons( HtmlTextWriter writer ) {
			foreach( CollapseBarItem item in this.Items ) {
				if ( item.Visible ) {

					Boolean itemIsCurrent = ( item.Title == this.ActiveItem );
			
					System.Web.UI.WebControls.Style itemStyle = new System.Web.UI.WebControls.Style();
					if ( itemIsCurrent ) {
						itemStyle.CopyFrom( this.CurrentButtonStyle );
					}
					itemStyle.MergeWith( this.ButtonStyle );

					itemStyle.AddAttributesToRender( writer );
					writer.AddStyleAttribute( "padding", "5px" );
					writer.RenderBeginTag( "div" );

					if ( itemIsCurrent ) {
						writer.Write( item.Title );
					} else {
						Button itemButton = new Button();
						itemButton.ID = this.UniqueID + ":" + item.Title;
						itemButton.Text = item.Title;
						itemButton.ForeColor = itemStyle.ForeColor;
						itemButton.BackColor = itemStyle.BackColor;
						itemButton.RenderControl( writer );
					}
				
					writer.RenderEndTag();

				}
			}
		}

		private void RenderDownLevelCurrentItem( HtmlTextWriter writer ) {

			foreach( CollapseBarItem item in this.Items ) {
				if ( item.Title == this.ActiveItem ) {

					if ( item.Visible ) {

						if ( !this.Height.IsEmpty ) {
							writer.AddStyleAttribute( "height", "100%" );
						}

						this.ContentStyle.AddAttributesToRender( writer );
						writer.RenderBeginTag( "div" );

						item.RenderControl( writer );

						writer.RenderEndTag();

					}

					break;
				}
			}
		}

		
		#endregion

		private Boolean RenderUpLevel {
			get {
				return this.Page != null && this.UplevelBrowser;
			}
		}

		private Boolean UplevelBrowser {
			get {
				if ( HttpContext.Current == null ) { return true; }

				return !( HttpContext.Current.Request.Browser.TagWriter.Equals( typeof( Html32TextWriter ) ) );
			}
		}

		#endregion

		#region ClientScript

		private static readonly String scriptKey = "CommunityServer.Controls.CollapseBar";
		private static readonly String arrayName = "CommunityServer_CollapseBars";

		private void RegisterClientScript() {
			if ( Page == null ) {
				return;
			}

			String currentItemIndex = "0";
			for( Int32 i = 0; i < this.Items.Count; i++ ) {
				CollapseBarItem item = this.Items[ i ];
				if ( item.Title == this.CurrentItem ) {
					currentItemIndex = i.ToString();
					break;
				}
			}

			this.Page.RegisterHiddenField( ClientSideCurrentItemTrackerID, currentItemIndex );

			if ( !Page.IsClientScriptBlockRegistered( scriptKey ) ) {
				this.Page.RegisterClientScriptBlock( scriptKey, String.Format( "<script type='text/javascript' language='javascript' src='{0}'></script>", Page.ResolveUrl( "~/Utility/CollapseBarScript.js" ) ) );
			}

			Page.RegisterArrayDeclaration( arrayName, "{ ID:'" + this.ClientID + "', InitialSelectedIndex:'" + currentItemIndex.ToString() + "', HiddenID:'" + ClientSideCurrentItemTrackerID + "', ItemCount:'" + this.Items.Count.ToString() + "' }" );

			if( !Page.IsStartupScriptRegistered( scriptKey ) ) {
				this.Page.RegisterStartupScript( scriptKey, String.Format( @"
<script type='text/javascript' language='javascript'>
<!--
CommunityServer_CollapseBar_Init( '{0}' );
//-->
</script>", this.Page.Request.ApplicationPath ) );
			}
		}

		#endregion

		#region State Cookie
		/// <summary>
		/// Loads state from the state cookie.
		/// </summary>
		protected virtual void LoadStateCookie() {
			HttpCookie cookie = this.Page.Request.Cookies[ StateCookieName ];
			if ( cookie != null ) {
				String savedState = cookie.Value;
				CollapseBarItem storedItem = this.ItemByIndex( savedState );
				if ( storedItem != null ) {
					this.CurrentItem = storedItem.Title;
				}
			}
		}

		/// <summary>
		/// Saves state to the state cookie.
		/// </summary>
		protected virtual void SaveStateCookie() {
			if ( this.Items.Count == 0 ) {
				return;
			}

			HttpCookie cookie = this.Page.Request.Cookies[ StateCookieName ];
			if ( cookie == null ) {
				cookie = new HttpCookie( StateCookieName );
			}

			for( Int32 i = 0; i < this.Items.Count; i++ ) {
				CollapseBarItem item = this.Items[ i ];
				if ( item.Title == this.ActiveItem ) {
					cookie.Value = i.ToString();
				}
			}

			cookie.Expires = System.DateTime.Now.Add( TimeSpan.FromDays( 30 ) );
			cookie.Path = this.Page.Request.ApplicationPath;
			this.Page.Response.Cookies.Add(cookie) ;
		}

		private String StateCookieName {
			get {
				return "CollapseBar:" + this.ClientID;
			}
		}
		#endregion

		#region IPostBackEventHandler Members

		/// <exclude/>
		public void RaisePostBackEvent(string eventArgument) {
			this.CurrentItem = eventArgument;
		}

		#endregion

		#region IPostBackDataHandler Members

		/// <exclude/>
		public void RaisePostDataChangedEvent() {
			// no event
		}

		/// <exclude/>
		public bool LoadPostData(string postDataKey, System.Collections.Specialized.NameValueCollection postCollection) {
			
			// Load from the hidden input set with clientside changes
			String hiddenInputValue = postCollection[ this.ClientSideCurrentItemTrackerID ];
			if ( hiddenInputValue != null ) {
				CollapseBarItem postedItem = this.ItemByIndex( hiddenInputValue );
				if ( postedItem != null && this.CurrentItem != postedItem.Title ) {
					this.CurrentItem = postedItem.Title;
					return false;
				}
			}

			// Load from a click on a title, from a downlevel browser
			foreach( CollapseBarItem item in this.Items ) {
				if ( postCollection[ postDataKey + ":" + item.Title ] != null ) {
					this.CurrentItem = item.Title;
					return false;
				}
			}

			return false;
		}

		private CollapseBarItem ItemByIndex( String itemIndex ) {
			try {
				Int32 index = Int32.Parse( itemIndex );
				if ( 0 <= index && index < this.Items.Count ) {
					return this.Items[ index ];
				}
			} catch( System.FormatException ex ) {
				System.Diagnostics.Debug.WriteLine( ex );
			}
			return null;
		}

		#endregion
	}

}
